// ===============================================
// core_kit_marquee
//
// Create by will on 3/13/21 3:43 PM
// Copyright @flutter_core_kit.All rights reserved.
// ===============================================

import 'dart:async';
import 'package:flutter/material.dart';

class CoreKitMarquee extends Marquee {
  CoreKitMarquee({
    Key? key,
    required final List<Widget> children,
    final Axis? scrollAxis,
    final double? ratioOfBlankToScreen,
    final double? moveDistance,
  }) : super(
          key: key!,
          children: children,
          scrollAxis: scrollAxis ?? Axis.horizontal,
          ratioOfBlankToScreen: ratioOfBlankToScreen ?? 0.25,
          moveDistance: moveDistance ?? 3.0,
        );

  CoreKitMarquee.build({
    Key? key,
    required final IndexedWidgetBuilder itemBuilder,
    required final int itemCount,
    final Axis? scrollAxis,
    final double? ratioOfBlankToScreen,
    final double? moveDistance,
  }) : super(
          key: key!,
          itemBuilder: itemBuilder,
          itemCount: itemCount,
          scrollAxis: scrollAxis ?? Axis.horizontal,
          ratioOfBlankToScreen: ratioOfBlankToScreen ?? 0.25,
          moveDistance: moveDistance ?? 3.0,
        );
}

class Marquee extends StatefulWidget {
  final IndexedWidgetBuilder? itemBuilder;
  final int? itemCount;
  final List<Widget>? children;

  ///滚动方向，水平或者垂直
  final Axis? scrollAxis;

  ///空白部分占控件的百分比
  final double? ratioOfBlankToScreen;

  // 播放速度 时间
  final double? moveDistance;

  Marquee({
    Key? key,
    this.scrollAxis,
    this.ratioOfBlankToScreen,
    this.itemBuilder,
    this.itemCount,
    this.children,
    this.moveDistance,
  });

  @override
  State<StatefulWidget> createState() {
    return MarqueeState();
  }
}

class MarqueeState extends State<Marquee> with SingleTickerProviderStateMixin {
  late ScrollController scroController;
  double? screenWidth;
  double? screenHeight;
  double position = 0.0;
  late Timer timer;
  final int _timerRest = 100;
  GlobalKey _key = GlobalKey();

  @override
  void initState() {
    super.initState();
    scroController = ScrollController();
    WidgetsBinding.instance!.addPostFrameCallback((callback) {
      startTimer();
    });
  }

  void startTimer() {
    double widgetWidth =
        _key.currentContext!.findRenderObject()!.paintBounds.size.width;
    double widgetHeight =
        _key.currentContext!.findRenderObject()!.paintBounds.size.height;

    timer = Timer.periodic(Duration(milliseconds: _timerRest), (timer) {
      double maxScrollExtent = scroController.position.maxScrollExtent;
      double pixels = scroController.position.pixels;
      if (pixels + widget.moveDistance! >= maxScrollExtent) {
        if (widget.scrollAxis == Axis.horizontal) {
          position = (maxScrollExtent -
                      screenWidth! * widget.ratioOfBlankToScreen! +
                      widgetWidth) /
                  2 -
              widgetWidth +
              pixels -
              maxScrollExtent;
        } else {
          position = (maxScrollExtent -
                      screenHeight! * widget.ratioOfBlankToScreen! +
                      widgetHeight) /
                  2 -
              widgetHeight +
              pixels -
              maxScrollExtent;
        }
        scroController.jumpTo(position);
      }
      position += widget.moveDistance!;
      scroController.animateTo(position,
          duration: Duration(milliseconds: _timerRest), curve: Curves.linear);
    });
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    screenWidth = MediaQuery.of(context).size.width;
    screenHeight = MediaQuery.of(context).size.height;
  }

  List<Widget> getBothEndsChild() {
    final List<Widget> children = <Widget>[];
    for (Widget w in widget.children!) {
      children.add(w);
    }
    children.add(getCenterChild());
    return children;
  }

  Widget getCenterChild() {
    if (widget.scrollAxis == Axis.horizontal) {
      return Container(width: screenWidth! * widget.ratioOfBlankToScreen!);
    } else {
      return Container(height: screenHeight! * widget.ratioOfBlankToScreen!);
    }
  }

  @override
  void dispose() {
    super.dispose();
    timer.cancel();
  }

  @override
  Widget build(BuildContext context) {
    if (widget.itemBuilder != null) {
      return ListView.builder(
        key: _key,
        scrollDirection: widget.scrollAxis!,
        controller: scroController,
        physics: NeverScrollableScrollPhysics(),
        itemBuilder: (buildContext, index) {
          if (index < widget.itemCount!) {
            return widget.itemBuilder!(buildContext, index);
          } else {
            return getCenterChild();
          }
        },
        itemCount: widget.itemCount! + 1,
      );
    } else {
      return ListView(
        key: _key,
        scrollDirection: widget.scrollAxis!,
        controller: scroController,
        physics: NeverScrollableScrollPhysics(),
        children: getBothEndsChild(),
      );
    }
  }
}
